//////////////////////////////////////////////////////////////////////////////////
//	 Copyright 2011 by Yosef Grabivker, ryuho@homenetworksoft.com
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//////////////////////////////////////////////////////////////////////////////////

#include <wx/wx.h>
#include <sstream>
#include "utils.h"
#include "logicmanager.h"
#include "linuxshellcmdprocessor.h"
#include "scriptgenerator.h"
#include "../common/MarkupSTL.h"


CLinuxShellCmdProcessor::CLinuxShellCmdProcessor(CLinkGuard& link):m_link(link)
{
	u_=n_=s_=i_=w_=x_=y_=z_=0;

	//Test grep availability
	RTSTRING rtStr = m_link->SendCmd( wxT(GREP_CMD) );

	// grepgrep: not found
	if ( std::string::npos==rtStr.find(NO_SUCH_FILE) &&
		std::string::npos==rtStr.find("not found") &&
		std::string::npos==rtStr.find("not recognized") )
	{
		m_bGrepSupported = true;
	}
	else
	{
		m_bGrepSupported = false;
	}
}

CLinuxShellCmdProcessor::~CLinuxShellCmdProcessor(void)
{
	if ( m_link->IsLoggedOn() )
	{
		m_link->SendCmd(STR_EXIT_CMD);
		m_link->SendCmd(STR_LOGOUT_CMD);
	}
}

void CLinuxShellCmdProcessor::Initialize()
{
	//Init IP tables
	SendActionToRouter(CScriptGenerator::GenerateStartUpScript());
}

RTSTRING CLinuxShellCmdProcessor::GetCaps()
{
	CMarkupSTL	doc;

	doc.AddElem( SHELL_CAPS_EL );

	doc.AddAttrib( GLOBAL_NAME_ATR,		"Linux"  );

	doc.AddAttrib( SHELL_SCRIPT_FORMAT,	SCRIPT_FORMAT_NATIVE_VAL );
	doc.AddAttrib( SHELL_MAC_FILTER,	GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_PING,			GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_PORT_FORWARD,	GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_BANDWIDTH,		GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_CONNECTIONS,	GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_TCPNAT_SETTNGS,GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_PROCKILL,		GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_SYSLOGCONFIG,	GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_KERNELMOD,		GLOBAL_ENABLE_VAL );

	doc.AddAttrib( SHELL_NAT_USAGE,		GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_MEM_USAGE,		GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_CPU_USAGE,		GLOBAL_ENABLE_VAL );
	doc.AddAttrib( SHELL_RT_USAGE,		GLOBAL_ENABLE_VAL );
	
	return doc.GetDoc();
}

void CLinuxShellCmdProcessor::DispatchCmd(const COMMANDREQUEST& cmd, COMMANDRESPONSE& cmdOut,
								bool& bNotify)
{
	bNotify = false;

	cmdOut.subCode = cmd.subCode;

	switch( cmd.code )
	{
		case cCmdConntracMax:
			OnGetConntracMax(cmdOut, bNotify);
		break;

		case cCmdGetSlabTable:
			OnGetSlabTable(cmdOut, bNotify);
		break;

		case cCmdMemMax:
			OnGetMemMax(cmdOut, bNotify);
		break;

		case cCmdMemVal:
			OnGetMemCur(cmdOut, bNotify);
		break;

		case cCmdRTCacheMax:
			OnGetRTCacheMax(cmdOut, bNotify);
		break;

		case cCmdRTCacheVal:
			OnGetRTCacheVal(cmdOut, bNotify);
		break;

		case cCmdCPU:
		{
			//store base values first
			if (!tot_frme_) OnGetCPU(cmdOut, bNotify);

			OnGetCPU(cmdOut, bNotify);
		}
		break;

		case cCmdScript:
			OnExecuteScript( cmd.strScript, cmdOut, bNotify);
		break;

		case cCmdConntrTableEntries:
			OnGetConntracTableEnt( cmdOut, bNotify);
		break;

		case cCmdInterfaceStat:
			OnGetInterfaceStat( cmdOut, bNotify);
		break;

		case cCmdARPTable:
			OnGetARPTable( cmdOut, bNotify);
		break;

		case cCmdGetIPConfig:
			OnGetIpConfig( cmdOut, bNotify);
		break;

		case cCmdGetRoutingTable:
			OnGetRoutingTable( cmdOut, bNotify);
		break;

		case cCmdGetRouterWANAddress:
		{
			OnGetIpConfig( cmdOut, bNotify);

			if ( bNotify )
			{
				RTSTRING strIPTable = cmdOut.strData;

				OnGetRoutingTable( cmdOut, bNotify);

				if ( bNotify )
				{
					RTSTRING strRoutingTable = cmdOut.strData; 
					OnGetRouterWANAddress( strIPTable, strRoutingTable, cmdOut, bNotify);
				}
			}
		}
		break;

		case cCmdGetRouterID:
		{
			int nRet(3);

			while(nRet-->0)
			{
				try
				{
					OnGetRouterID( cmdOut, bNotify);
					break;

				}catch(...) {}
			}
		}
		break;

		case cCmdGetTCPTimeOuts:
		{
			OnGetTCPTimeOuts( cmdOut, bNotify);
		}
		break;

		//Do nothing, TODO: check logic here
		case cCmdMACBlockExecuted:
		break;


		case cCmdGetVersion:
			OnGetVersion( cmdOut, bNotify);
		break;

		case cCmdFlushRTTable:
			OnFlushRTTable( cmdOut, bNotify);
		break;

		case cCmdPing:
			OnPing(cmd.strScript, cmdOut, bNotify);
		break;

		case cCmdGetProcessList:
			OnGetProcList(cmdOut, bNotify);
		break;

		case cCmdPFTableUpdated:
		case cCmdSysLogMessage:
		break;

		default:
			assert(0);
		break;
	}
}

//////////////////////////////////////////////////////////////////////////
//Get Maximum number of NAT connections
//read: /proc/sys/net/ipv4/netfilter/ip_conntrack_max
void CLinuxShellCmdProcessor::OnGetConntracMax(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = true;
	long lVal = ReadNumberProc(PATH_CONTRACK_MAX);

	cmdOut.code = cCmdConntracMax;
	cmdOut.lData= lVal;
}


//////////////////////////////////////////////////////////////////////////
// Get NAT memory usage 
//read: /proc/slabinfo
//understanding after reading the source:
//understanding after reading the source:
//
//                  active-objects
//                  |      allocated-objects
//                  |      |         object-size
//                  |      |         |   active-slab-allocations
//                  |      |         |   |     total-slab-allocations
//                  |      |         |   |     |        alloc-size
//                  |      |         |   |     |        |
//inode_cache       423370 423556    512 60482 60508    1 :  248   62
//                                                           |     |
//                                                       limit     |
//                                                       batch-count
//# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <batchcount> <limit> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
//ip_conntrack         973			1000		384		10				1 :			tunables   54			27		0 :				 slabdata    100			100      0
void CLinuxShellCmdProcessor::OnGetSlabTable(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;
	long lVal;

	RTSTRING strData = m_link->ReadFile(PATH_CONTRACK_NO_GRP);
	lVal = CLogicManager::ToNumberValIfLineHave(strData, PATH_CONTRACK_NO_GRP_VAL);


	cmdOut.code = cCmdGetSlabTable;
	cmdOut.lData= lVal;
	cmdOut.strData = strData;

	bNotify = true;

}

//////////////////////////////////////////////////////////////////////////
// Get maximum router's physical memory 
void CLinuxShellCmdProcessor::OnGetMemMax(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;
	long lVal;

	RTSTRING strData = m_link->ReadFile(CMD_MEM_TOTAL_NO_GRP);
	lVal = CLogicManager::ToNumberValIfLineHave(strData, CMD_MEM_TOTAL_NO_GRP_VAL);

	if ( lVal )
	{
		cmdOut.code = cCmdMemMax;
		cmdOut.lData= lVal;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

//////////////////////////////////////////////////////////////////////////
//Get memory usage
void CLinuxShellCmdProcessor::OnGetMemCur(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->ReadFile(CMD_MEM_TOTAL_NO_GRP);

	long lVal = CLogicManager::ToNumberValIfLineHave(strData, CMD_MEM_TOTAL_NO_GRP_VAL);
	long lValFree = CLogicManager::ToNumberValIfLineHave(strData, CMD_MEM_FREE_NO_GRP_VAL);

	if ( lVal&lValFree )
	{
		cmdOut.code = cCmdMemVal;
		cmdOut.lData= lVal-lValFree;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

//////////////////////////////////////////////////////////////////////////
// Get max size of routing cache
void CLinuxShellCmdProcessor::OnGetRTCacheMax(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = true;

	long lVal = ReadNumberProc(CMD_RT_CACHE_TOTAL);

	cmdOut.code = cCmdRTCacheMax;
	cmdOut.lData= lVal;
}

//////////////////////////////////////////////////////////////////////////
// Get routing cache usage
void CLinuxShellCmdProcessor::OnGetRTCacheVal(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;
	long lVal;

	if ( m_link->HaveGrep() )
	{
		lVal = ReadNumberProc(CMD_RT_CACHE_CUR_GRP);
	}
	else
	{
		lVal = ReadNumberProcFromLine(CMD_RT_CACHE_CUR_NO_GRP, CMD_RT_CACHE_CUR_NO_GRP_VAL);
	}

	if ( lVal )
	{
		cmdOut.code = cCmdRTCacheVal;
		cmdOut.lData= lVal;
		bNotify = true;
	}
}

//////////////////////////////////////////////////////////////////////////
// Get CPU usage
void CLinuxShellCmdProcessor::OnGetCPU(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	#define TRIMz(x)  ((tz = (long long)(x)) < 0 ? 0 : tz)

	bNotify = false;
	int num;

	RTSTRING strData;

	if ( m_link->HaveGrep() )
	{
		strData = m_link->ReadFile(CMD_CPU_TOTAL_GREP);
	}
	else
	{
		RTSTRING str = m_link->ReadFile(CMD_CPU_TOTAL_NO_GRP);
		strData = CLogicManager::GetStringWithPattern(str, CMD_CPU_TOTAL_NO_GRP_VAL);
	}

	if ( !strData.empty() )
	{
		unsigned long long u(0),n(0),s(0),i(0),w(0),x(0),y(0),z(0); 

		unsigned long long lVals[4];
		num = CLogicManager::StringToDigit(strData, lVals, 4 );

		u = lVals[0];
		n = lVals[1];
		s = lVals[2];
		i = lVals[3];

		if ( num >= 4 )
		{
			long long u_frme, s_frme, n_frme, i_frme, w_frme, x_frme, y_frme, z_frme, tz, tot_frme, tot_load;

			u_frme = u - u_;
			s_frme = s - s_;
			n_frme = n - n_;
			i_frme = TRIMz(i - i_);
			w_frme = w - w_;
			x_frme = x - x_;
			y_frme = y - y_;
			z_frme = z - z_;
			tot_frme = u_frme + s_frme + n_frme + i_frme + w_frme + x_frme + y_frme + z_frme;
			tot_load = u_frme + s_frme + n_frme + w_frme + x_frme + y_frme + z_frme;

			if (tot_frme < 1) tot_frme = 1;
			if (tot_load < 1) tot_load = 1;

			cmdOut.code = cCmdCPU;
			cmdOut.lData  = (unsigned long)(tot_frme);
			cmdOut.lData1 = (unsigned long)(tot_load);
			bNotify = true;

			u_=u;
			n_=n;
			s_=s;
			i_=i;
			w_=w;
			x_=x;
			y_=y;
			z_=z;
			tot_frme_=tot_frme;
		}
	}	
}

//////////////////////////////////////////////////////////////////////////
//Send command sequence to the shell for execution line by line
void CLinuxShellCmdProcessor::OnExecuteScript(const wxString& strScript, COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	RTSTRING strData;
	wxString scr=strScript, scrLine=strScript;
	int nPos;

	do 
	{
		nPos = scr.Find( wxT(TELNET_ENTER) );

		if (-1!=nPos)
		{
			scrLine = scr.Left(nPos);
			scr.Remove(0, nPos );
			scr.Trim(false);
		}

		if ( scrLine.empty() )
		{
			break;
		}

		strData+= m_link->SendCmd( scrLine );

		wxThread::Sleep(150);

	} while ( -1!=nPos && !scr.empty() );

	cmdOut.code = cCmdScript;
	cmdOut.strData = strData;

	bNotify = true;
}


//////////////////////////////////////////////////////////////////////////
// Read connection list from NAT
//icmp     1	9	src=192.168.1.2 dst=74.125.127.100 type=8 code=0 id=512 [UNREPLIED] src=74.125.127.100 dst=79.176.36.89 type=0 code=0 id=512 use=1
//udp      17	51 	src=192.168.1.2 dst=78.174.165.236 sport=21000 dport=57200 src=78.174.165.236 dst=79.176.36.89 sport=57200 dport=21000 [ASSURED] use=1
//tcp      6	85	ESTABLISHED src=95.215.185.204 dst=79.176.36.89 sport=1754 dport=21000 src=192.168.1.2 dst=95.215.185.204 sport=21000 dport=1754 use=1
//tcp      6	20	TIME_WAIT src=123.243.176.79 dst=79.179.34.55 sport=59617 dport=21000 src=192.168.1.2 dst=123.243.176.79 sport=21000 dport=59617 use=1
void CLinuxShellCmdProcessor::OnGetConntracTableEnt(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	cmdOut.code = cCmdConntrTableEntries;
	cmdOut.strData = m_link->ReadFile(PATH_CONTRACK_TABLE);

	size_t nPos = cmdOut.strData.find(NO_SUCH_FILE);
	if ( nPos!=std::string::npos)
	{
		bNotify = false;
	}
	else
	{
		CMarkupSTL	doc;
		doc.AddElem( CONLIST_ROOT_EL );

		std::stringstream sIn( (cmdOut.strData+"\n").c_str() );
		{
			char buf[512];
			while ( !sIn.getline(buf, sizeof(buf)).eof() )
			{
				CONNTRACENTRY entry;
				if ( ParseEntry( buf, entry ) )
				{
					doc.AddChildElem( GLOBAL_ENTRY_EL );

					doc.AddChildAttrib(CONLIST_PROTO_ATTR, entry.strProto.ToAscii()  );
					doc.AddChildAttrib(CONLIST_DST_IP_ATTR,  entry.strDst.ToAscii() );
					doc.AddChildAttrib(CONLIST_DST_PORT_ATTR, entry.strDstPort.ToAscii() );
					doc.AddChildAttrib(CONLIST_SRC_IP_ATTR, entry.strSrc.ToAscii());
					doc.AddChildAttrib(CONLIST_SRC_PORT_ATTR, entry.strSrcPort.ToAscii());
					doc.AddChildAttrib(CONLIST_TTL_ATTR, entry.strTTL.ToAscii());
					doc.AddChildAttrib(CONLIST_STATUS_ATTR, entry.strStatus.ToAscii());
				}
			}
		}

		cmdOut.strXML = doc.GetDoc();

		bNotify = true;
	}
}

bool CLinuxShellCmdProcessor::ParseEntry( const char* szEntry, CONNTRACENTRY& entry )
{
	bool bRes(false);
	char buf[1024];
	char seps[]   = " \t\n\r";
	char *token;
	strncpy(buf, szEntry, sizeof(buf));
	token = strtok(buf, seps);

	int nTokNum=0;

	while( token != NULL && entry.strDstPort.IsEmpty() )
	{
		if ( entry.strProto.empty() &&
			NULL == strstr(token, "0x") )
		{
			bRes = true;
			entry.strProto = wxString::FromAscii( token );
			nTokNum = 0;
		}
		else if( isupper(token[0]) && entry.strStatus.empty() )
		{
			bRes = true;
			entry.strStatus = wxString::FromAscii( token );
		}
		else if (nTokNum==2 && isdigit(token[0]) )
		{
			bRes = true;
			entry.strTTL = wxString::FromAscii( token );
		}
		else
		{
			bRes|=ParseToken( token, entry );
		}

		// Get next token: 
		token = strtok( NULL, seps ); // C4996
		nTokNum++;
	}

	return bRes;
}

bool CLinuxShellCmdProcessor::ParseToken( const char* szToken, CONNTRACENTRY& entry )
{
	if ( 0==memcmp(szToken, "src=",4) )
	{
		entry.strSrc = wxString::FromAscii( szToken+4);
		return true;
	}

	if ( 0==memcmp(szToken, "dst=",4) )
	{
		entry.strDst = wxString::FromAscii( szToken+4);
		return true;
	}

	if ( 0==memcmp(szToken, "sport=",6) )
	{
		entry.strSrcPort = wxString::FromAscii( szToken+6);
		return true;
	}

	if ( 0==memcmp(szToken, "dport=",6) )
	{
		entry.strDstPort = wxString::FromAscii( szToken+6);
		return true;
	}

	return false;
}
//-----------------------------------------------------------------------------------




//////////////////////////////////////////////////////////////////////////
// Get per interface statistic

//Inter-|   Receive                                                |  Transmit
//face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
//lo: 2776770   11307    0    0    0     0          0         0  2776770   11307    0    0    0     0       0          0
//eth0: 1215645    2751    0    0    0     0          0         0  1782404    4324    0    0    0   427       0          0
//ppp0: 1622270    5552    1    0    0     0          0         0   354130    5669    0    0    0     0       0          0
//tap0:    7714      81    0    0    0     0          0         0     7714      81    0    0    0     0       0          0
void CLinuxShellCmdProcessor::OnGetInterfaceStat(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->ReadFile(CMD_INTERFACE_STAT);

	if ( !strData.empty() )
	{
		PROCTABLEWITHHEADER pt = CLogicManager::ParseTableWithHeaders( strData );

		if ( pt.headers.empty() ) return;
		if ( pt.rows.empty() ) return;

		CMarkupSTL	doc;
		doc.AddElem( INTSTAT_ROOT_EL );

		for(size_t i=0;i<pt.rows.size();i++)
		{
			doc.AddChildElem( GLOBAL_ENTRY_EL);
			doc.AddChildAttrib(GLOBAL_NAME_ATR, CLogicManager::GeValFromTable( pt, "face", i, 0 ).ToAscii() );
			doc.AddChildAttrib(GLOBAL_RECV_ATR, CLogicManager::GeValFromTable( pt, "bytes", i, 0 ).ToAscii() );
			doc.AddChildAttrib(GLOBAL_TRNSM_ATR, CLogicManager::GeValFromTable( pt, "bytes", i, 1 ).ToAscii() );
		}

		cmdOut.strXML	= doc.GetSubDoc();
		cmdOut.code		= cCmdInterfaceStat;
		cmdOut.strData	= strData;
		bNotify = true;
	}
}


//IP address       HW type     Flags       HW address            Mask     Device
//10.0.0.2         0x1         0x0         00:00:00:00:00:00     *        br0
//10.0.0.4         0x1         0x2         6C:F0:49:45:3F:C9     *        br0
void CLinuxShellCmdProcessor::OnGetARPTable(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->ReadFile(CMD_ARP_TABLE);

	if ( !strData.empty() )
	{
		cmdOut.code = cCmdARPTable;
		cmdOut.strData = strData;
		bNotify = true;

		CMarkupSTL	doc;
		doc.AddElem( ARP_ROOT_EL );

		PROCTABLEWITHHEADER table = CLogicManager::ParseTableWithHeaders( strData, 6, " \n\t" );

		for ( size_t i=0;i<table.rows.size();i++)
		{
			doc.AddChildElem( GLOBAL_ENTRY_EL );

			wxString strIP = CLogicManager::GeValFromTable(table, "IP address", i, 0 );
			doc.AddChildAttrib( GLOBAL_IP_ATTR, strIP.ToAscii() );
			
			wxString strMAC = CLogicManager::GeValFromTable(table, "HW address", i, 0 );
			doc.AddChildAttrib( GLOBAL_MAC_ATTR, strMAC.ToAscii() );
		}

		cmdOut.strXML = doc.GetDoc();
	}
}


void CLinuxShellCmdProcessor::OnGetIpConfig(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->SendCmd(CMD_GET_IP_SETTINGS);

	if ( !strData.empty() )
	{
		cmdOut.code = cCmdGetIPConfig;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

//UNUSED
//Iface   Destination     Gateway         Flags   RefCnt  Use     Metric  Mask            MTU     Window  IRTT                                                       
//ppp_0_8_48_1    D4B32501        00000000        0005    0       0       0       FFFFFFFF        0       0       0                                                                       
//br0     0A000000        00000000        0001    0       0       0       FFFFFF00        0       0       0                                                                                
//ppp_0_8_48_1    00000000        D4B32501        0003    0       0       0       00000000        0       0       0                                                                       
void CLinuxShellCmdProcessor::OnGetRoutingTable(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	wxString strFileName = wxString::FromAscii(DEF_RT_PATH);

	RTSTRING strData = m_link->ReadFile(strFileName);

	if ( !strData.empty() )
	{
		cmdOut.code = cCmdGetRoutingTable;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

void CLinuxShellCmdProcessor::OnGetRouterWANAddress( const RTSTRING& strIPTable, const RTSTRING& strRoutingTable,
										  COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;
	cmdOut.code = cCmdGetRouterWANAddress;

	try
	{
		PROCTABLEWITHHEADER pt = CLogicManager::ParseTableWithHeaders( strRoutingTable );

		if ( pt.headers.empty() ) return;
		if ( pt.rows.empty() ) return;

		wxString strIntName;
		wxString strDest;

		for(size_t i=0;i<pt.rows.size();i++)
		{
			strIntName = CLogicManager::GeValFromTable( pt, "Iface", i, 0 );
			strDest    = CLogicManager::GeValFromTable( pt, "Destination", i, 0 );

			long l =0;

			if ( strDest.ToLong(&l, 16) && !l)
				break;

			strIntName = wxT("");
		}

		if ( !strIntName.IsEmpty() )
		{
			RTSTRING strIPAddrString = CLogicManager::GetNextStringWithPattern(strIPTable, (const char*)strIntName.ToAscii());

			size_t tPos = strIPAddrString.find("addr:");
			size_t tPosSpace = strIPAddrString.find(" ", tPos);

			if ( std::string::npos!=tPos && std::string::npos!=tPosSpace)
			{
				std::string strIP = strIPAddrString.substr(tPos+5, tPosSpace-tPos-5);

				if ( !strIP.empty() )
				{
					bNotify = true;
					cmdOut.strData = strIP;
				}
			}
		}
	}
	catch(...) {}
}

void CLinuxShellCmdProcessor::OnGetRouterID(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;
	cmdOut.code = cCmdGetRouterID;
	cmdOut.lData = CODE_GET_MAC_FAIL;

	RTSTRING strData;
	wxString strMAC;

	//Get Mac from eth0
	int nTry(1);

	do
	{
		strData = m_link->SendCmd(CMD_GET_ROUTER_ID);
		strMAC = ExtractMACFromString( wxString::FromAscii(strData.c_str()) );
	}
	while(nTry-->0 && strMAC.empty() );

	if ( strMAC.empty() )
	{
		nTry = 2;

		do
		{
			strData = m_link->SendCmd(wxT("ifconfig"));
		}
		while(nTry-->0 && strData.empty() );

		if ( !strData.empty() )
		{
			RTSTRING rtLine;

			rtLine = CLogicManager::GetStringWithPattern(strData,  "eth0");
			if ( !rtLine.empty() ) strMAC = ExtractMACFromString( wxString::FromAscii(rtLine.c_str()) );

			if ( rtLine.empty() || strMAC.empty() ) rtLine = CLogicManager::GetStringWithPattern(strData,  "wl0");
			if ( !rtLine.empty() ) strMAC = ExtractMACFromString( wxString::FromAscii(rtLine.c_str()) );

			if ( rtLine.empty() || strMAC.empty() ) rtLine = CLogicManager::GetStringWithPattern(strData,  "br0");
			if ( !rtLine.empty() ) strMAC = ExtractMACFromString( wxString::FromAscii(rtLine.c_str()) );
		}
	}

	//Get Mac from br0==eth0
	if ( strMAC.empty() )
	{
		nTry = 3;

		do
		{
			strData = m_link->SendCmd(wxT("ifconfig br0"));
			strMAC = ExtractMACFromString( wxString::FromAscii(strData.c_str()) );
		}
		while(nTry-->0 && strMAC.empty() );
	}

	if ( strMAC.empty() )
	{
		strData = m_link->SendCmd(CMD_GET_ROUTER_ID_ALT);

		if ( strData.empty() )
		{
			cmdOut.strData = "not found";
		}
		else
		{
			//bind to CPU
			cmdOut.lData = CODE_GET_MAC_OK;
			cmdOut.strData = strData.substr(0, 50);
			size_t tPos = strData.find("BogoMIPS");

			if ( std::string::npos != tPos )
			{
				cmdOut.strData = strData.substr(0, tPos);
			}
		}
	}
	else
	{
		cmdOut.strData = (const char*)strMAC.ToAscii();
		cmdOut.lData = CODE_GET_MAC_OK;
	}

	if ( !cmdOut.strData.empty() )
	{
		assert(cmdOut.lData == CODE_GET_MAC_OK);
		bNotify = true;
	}
}

void CLinuxShellCmdProcessor::OnGetTCPTimeOuts(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	long lVal;

	bNotify = true;
	cmdOut.code = cCmdGetTCPTimeOuts;

	//Generic
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_generic_timeout") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stGeneric = (size_t)lVal;
	}

	//Established
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_established") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stESTABLISHED = (size_t)lVal;
	}

	//SYN_SENT
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_syn_sent") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stSYN_SENT = (size_t)lVal;
	}

	//SYN_RECV
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_syn_recv") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stSYN_RECV = (size_t)lVal;
	}

	//FIN_WAIT
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_fin_wait") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stFIN_WAIT = (size_t)lVal;
	}

	//TIME_WAIT
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_time_wait") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stTIME_WAIT = (size_t)lVal;
	}

	//CLOSE
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_close") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stCLOSE = (size_t)lVal;
	}

	//CLOSE_WAIT
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_close_wait") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stCLOSE_WAIT = (size_t)lVal;
	}

	//LAST_ACK
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_timeout_last_ack") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stLAST_ACK = (size_t)lVal;
	}

	//ip_conntrack_udp_timeout
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stUDP = (size_t)lVal;
	}

	//ip_conntrack_udp_timeout_stream
	lVal = ReadNumberProc( wxT("/proc/sys/net/ipv4/netfilter/ip_conntrack_udp_timeout_stream") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stUDPStream = (size_t)lVal;
	}

	//ip_conntrack_max
	lVal = ReadNumberProc( wxT("//proc/sys/net/ipv4/netfilter/ip_conntrack_max") );

	if ( lVal )
	{
		cmdOut.natTimeOuts.stMaxEntries = (size_t)lVal;
	}
}

void CLinuxShellCmdProcessor::OnGetVersion(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->ReadFile(CMD_GET_VERSION);

	if ( !strData.empty() )
	{
		cmdOut.code = cCmdGetVersion;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

void CLinuxShellCmdProcessor::OnFlushRTTable(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->SendCmd( wxString::FromAscii(CMD_FLUSH_RT_CACHE));

	if ( !strData.empty() )
	{
		cmdOut.code = cCmdFlushRTTable;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

void CLinuxShellCmdProcessor::OnPing(const wxString& strScript, COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	if ( !strScript.empty() )
	{
		RTSTRING strData = m_link->SendCmd( strScript, 10000 );

		if ( !strData.empty() )
		{
			cmdOut.code = cCmdPing;
			cmdOut.strData = strData;
			bNotify = true;
		}
	}
}
/////////////////////////////////////////////////////////////////////////


void CLinuxShellCmdProcessor::OnGetProcList(COMMANDRESPONSE& cmdOut, bool& bNotify)
{
	bNotify = false;

	RTSTRING strData = m_link->SendCmd( CMD_GET_PROCESS_LIST );

	if ( !strData.empty() )
	{
		cmdOut.code = cCmdGetProcessList;
		cmdOut.strData = strData;
		bNotify = true;
	}
}

//////////////////////////////////////////////////////////////////////////
//UTL
long CLinuxShellCmdProcessor::ReadNumberProc(const wxString& strPath)
{

	RTSTRING str = m_link->ReadFile(strPath);

	return CLogicManager::ToNumberVal(str);
}

long CLinuxShellCmdProcessor::ReadLinesProc(const wxString& strPath, RTSTRING& strData )
{
	long lVal(0);
	int nPos(0);

	strData = m_link->ReadFile(strPath);

	if ( !strData.empty() )
	{
		size_t pos = strData.find(NO_SUCH_FILE);
		if ( pos!=std::string::npos)
			return 0;

		do
		{
			nPos = strData.find('\n', nPos);
			lVal++;
			nPos++;
		}while( nPos );
	}

	return lVal;
}

long CLinuxShellCmdProcessor::ReadNumberProcFromLine(const wxString& strPath, const RTSTRING& strVal)
{
	RTSTRING strData = m_link->ReadFile(strPath);

	return CLogicManager::ToNumberValIfLineHave(strData, strVal);
}

void CLinuxShellCmdProcessor::SendActionToRouter(const wxString& str)
{
	COMMANDRESPONSE cmdOut;
	bool bNotify;

	OnExecuteScript( str, cmdOut, bNotify);	
}
